package org.test4j.tutorial.test.fluent;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.test4j.mock.Mocks;

import static org.junit.jupiter.api.Assertions.assertEquals;

@Mocks(InvocationFluentMockDemo.Service.class)
public class InvocationFluentMockDemo {
    InvocationFluentMockDemoMocks mocks = new InvocationFluentMockDemoMocks();

    @DisplayName("演示Mock方法执行原方法逻辑")
    @Test
    void test1() {
        mocks.Service().getString.restAnswer(inv -> inv.proceed() + ", plus mock info.");

        String result = new Service().getString();
        assertEquals("origin string, plus mock info.", result);
    }

    @DisplayName("演示按调用时序进行mock")
    @Test
    void test2() {
        mocks.Service().getString.thenReturn("mock 1", "mock 2").thenReturn("mock 3");
        Service service = new Service();
        assertEquals("mock 1", service.getString());
        assertEquals("mock 2", service.getString());
        assertEquals("mock 3", service.getString());
        assertEquals("origin string", service.getString());
        assertEquals("origin string", service.getString());
    }

    @DisplayName("对方法入参进行断言演示")
    @Test
    void test3() {
        mocks.Service().setString.restAnswer(inv -> {
            Assertions.assertEquals("期望值", inv.arg(0));
            return inv.proceed();
        });
        Service service = new Service();
        // 正常通过
        service.setString("期望值");
        // 设置其它值, 应该是抛出一个断言异常
        Assertions.assertThrows(AssertionError.class, () -> service.setString("其它值"));
    }

    @DisplayName("对方法出参进行断言演示")
    @Test
    void test4() {
        mocks.Service().getString.restAnswer(inv -> {
            String result = inv.proceed();
            Assertions.assertEquals("origin string", result);
            return result;
        });
        Service service = new Service();
        /**
         * 方法调用正常通过
         */
        service.getString();
        /**
         * 将返回值改为其它值, 方法调用应该抛出断言异常
         */
        service.setString("other value");
        Assertions.assertThrows(AssertionError.class, () -> service.getString());
    }

    static class Service {
        private String value = "origin string";

        public String getString() {
            return value;
        }

        public void setString(String input) {
            this.value = input;
        }
    }
}
